#pragma once

#include	<protocols/Core.pb.h>
#include	<Pool.h>
#include	<Singleton.h>
#include	<map>
#include	<string>

class OnlinePlayer {
public:
	OnlinePlayer(uint64_t at, const Core::RoleData & role)
		: _id(role.pid())
		, _at(at)
		, _account(role.account())
		, _name(role.name()) {}

	inline uint64_t Id() const { return _id; }
	inline const std::string & Account() const { return _account; }
	inline const std::string & Name() const { return _name; }

	/**
	 * Send message to server of mine. NOT directly to client of mine.
	 */
	bool Send(int pf, const google::protobuf::Message & msg, uint32_t serial = 0);

private:
	uint64_t _id;
	uint64_t _at;
	std::string _account;
	std::string _name;

	friend class OnlinePlayerManager;
};

class OnlinePlayerManager : public ISingleton<OnlinePlayerManager> {
public:
	OnlinePlayerManager() : _sessions(), _account2player(), _name2player(), _id2player(), _players(32) {}
	virtual ~OnlinePlayerManager() {}

	std::string CreateSession(const std::string & account);
	int CheckSession(const std::string & account, const std::string & session);
	void ClearSession(const std::string & account);

	OnlinePlayer * Launch(uint64_t at, const Core::RoleData & role);
	OnlinePlayer * Find(const std::string & name);
	OnlinePlayer * Find(uint64_t id);
	OnlinePlayer * FindByAccount(const std::string & account);

	void Rename(OnlinePlayer * player, const std::string & name);
	void Logout(uint64_t id);
	void Kickout(OnlinePlayer * player, int reason);
	void Kickout(uint64_t id, int reason);

private:
	std::map<std::string, std::string> _sessions;
	std::map<std::string, OnlinePlayer *> _account2player;
	std::map<std::string, OnlinePlayer *> _name2player;
	std::map<uint64_t, OnlinePlayer *> _id2player;
	Pool<OnlinePlayer> _players;
};

#define	GOnlinePlayer	OnlinePlayerManager::Instance()